# _*_coding:utf-8_*_
import logging
import time

import pyvisa as visa
import os
import pathlib
import traceback
import serial
from utils.log_util import loggings
from ATS.errHandler import errHandler
from . import pyvisaFake
import sys

ERR_ARGS = 21800
TIMEOUT = 21801
ERR_CALL = 21802
OK = 0


# workpath = pathlib.Path(sys.argv[0])
# print("1111",workpath)
# workpath1 = os.path.dirname(os.path.realpath(sys.argv[0]))
# sys.path.insert(0, os.path.dirname(workpath1))


# sys.path.insert(0, str(pathlib.PurePath(workpath)))
# print(sys.path)


class PyvisaImpl(pyvisaFake.PyvisaFake):
    def __init__(self, comm_type, **args):
        self.comm_type = comm_type
        # comm_type = inst_infodict.get("interface_type")
        try:
            visa.log_to_screen(level=logging.ERROR)
            if comm_type == 'GPIB':
                addr = args.get('addr', None)
                self.addr = addr
                GPIB_card = args.get('card', 'GPIB0')

                self.instrHandle = visa.ResourceManager().open_resource(
                    "%s::%s::INSTR" % (GPIB_card, addr))  # ,term_chars=term_chars)

            elif comm_type == 'RS232':
                com = args.get('addr', None)
                self.com = com
                baud = args.get('baud', None)
                self.instrHandle = serial.Serial(port=com, baudrate=9600, bytesize=8, parity="N", stopbits=1)
                self.com_cls()
            elif comm_type == 'LAN':
                addr = args.get('lan_addr', '127.0.0.1')
                self.addr = addr
                # print("self.addr",self.addr)
                self.instrHandle = visa.ResourceManager().open_resource(self.addr)
                # print("self.instrHandle",self.instrHandle)
                self.instrHandle.read_termination = '\n'
                self.instrHandle.write_termination = '\n'
                self.instrHandle.timeout = 600000
            elif comm_type == 'USB':
                addr = args.get('usb_addr', None)
                self.addr = addr
                self.instrHandle = visa.ResourceManager().open_resource(self.addr)
        except Exception as e:
            print(traceback.format_exc())
            loggings.error("pyvisaImplError,init visa.instrument failed " + str(e))
            pyvisaFake.PyvisaFake.__init__(self)
            raise e

    def get_instr_lable(self):
        if self.comm_type == 'GPIB' or self.comm_type == 'LAN':
            return str(self.addr)
        elif self.comm_type == 'RS232':
            return str(self.com)
        else:
            return None

    def get_instrHandle(self):
        return self.instrHandle

    def inWaiting(self):
        n = self.instrHandle.inWaiting()
        return n

    def com_cls(self):
        # 清空输入和输出流,該方法適用於串口通信
        self.instrHandle.flushInput()
        self.instrHandle.flushOutput()
        return 0

    def rs_read(self, n):
        val = self.instrHandle.read(n)
        return val

    def write(self, msg):
        """
        writes the string message to the instrument
        """
        try:
            self.instrHandle.write(msg)
            # self.queryErrorState()
            loggings.info("visa write command success" + "\n" + str(self.instrHandle))

        except Exception as e:
            loggings.error(
                "pyvisaImplError,visa.write error " + str(msg) + "\n" + str(e) + "\n" + str(self.instrHandle))
            raise e

    def read_values(self, formats=None):
        """
        returns a list of decimal values (floats) sent from the instrument to the computer. See section 1.2 above. The list
        may contain only one element or may be empty.
        The optional format argument overrides the setting of values format
        """
        try:
            if formats is None:
                vals = self.instrHandle.read_values()
            else:
                vals = self.instrHandle.read_values(formats)
            loggings.info("visa write command success")
            return vals
        except Exception as e:
            loggings.error("visa write command success " + str(e))
            raise e

    def read(self):
        """
        returns a string sent from the instrument to the computer.
        """
        try:
            val = self.instrHandle.read()
            loggings.info("visa read command success")
            return val
        except Exception as e:
            loggings.info("visa read command fail " + str(e))
            raise e

    def query_binary_values(self, msg):
        """
        查询二进制块数据的指令，返回解析后的列表数据
        :param msg: 指令
        :return:list
        """
        try:
            data = self.queryBinaryWithoutCheckingErrorState(msg)
            # self.queryErrorState()
            return data
        except Exception as e:
            loggings.error("query_binary_values failed " + str(e))
            raise e

    def ask(self, msg):
        """
        sends the string message to the instrument and returns the answer string from the instrument
        """
        try:
            val = self.queryWithoutCheckingErrorState(msg)
            # self.queryErrorState()
            loggings.info("visa query command success")
            return val
        except Exception as e:
            loggings.error("visa query command failed " + str(e))
            raise e

    def setWithoutCheckingErrorState(self, command):
        try:
            self.instrHandle.write(command)
        except BaseException as e:
            loggings.error("setWithoutCheckingErrorState fail " + str(e))
            raise e

    def queryBinaryWithoutCheckingErrorState(self, command):
        try:
            return self.instrHandle.query_binary_values(command, data_points=20000)
        except BaseException as e:
            loggings.error("queryBinaryWithoutCheckingErrorState fail " + str(e))
            raise e

    def queryWithoutCheckingErrorState(self, command):
        try:
            result = self.instrHandle.query(command)
            if result:
                return result
            loggings.info("queryWithoutCheckingErrorState" + str(command))
        except Exception as e:
            loggings.error("queryWithoutCheckingErrorState fail " + str(e))
            raise e

    def queryErrorState(self):
        try:
            self.__checkSystemError()
            self.__checkOperationComplete()
        except Exception as e:
            loggings.error("queryErrorState fail " + str(e))
            raise e

    def __checkSystemError(self):
        error_msg = self.queryWithoutCheckingErrorState("system:error?").strip()
        if error_msg != "0, \"No error\"" and error_msg != "+0,\"No error\"" and error_msg != "+0,\"NO ERROR\"":
            # 抛出異常
            loggings.error("__checkSystemError fail " + str(error_msg))
            # raise ValueError(error_msg)

    def __checkOperationComplete(self):

        while True:
            opc_star = self.queryWithoutCheckingErrorState("*OPC?").strip()
            if opc_star != "1" and opc_star != "+1":
                continue
            else:
                break

    def set_timeout(self, timeout):
        try:
            self.instrHandle.timeout = timeout
            loggings.info("visa set_timeout command success")
            return OK
        except Exception as e:
            loggings.error("visa set_timeout command fail " + str(e))
            return e

    def ask_for_values(self, msg, formats=None):
        """
        sends the string message to the instrument and reads the answer as a list of values, just as read values()
        does.
        The optional format argument overrides the setting of values format
        """
        try:
            if formats is None:
                vals = self.instrHandle.ask_for_values(msg)
            else:
                vals = self.instrHandle.ask_for_values(msg, formats)
            loggings.info("visa ask_for_values command success ")
            return vals
        except Exception as e:
            loggings.error("visa ask_for_values command fail " + str(e))
            return e

    def wait_for_srq(self, timeout=25):
        """
        Only for GPIB mode
        """
        if self.comm_type != 'GPIB':
            return ERR_CALL
        try:
            status = self.instrHandle.wait_for_srq(timeout)
            loggings.info("visa wait_for_srq command success ")
            return status
        except Exception as e:
            loggings.error("visa wait_for_srq command fail " + str(e))
            raise e

    def spoll(self):
        if self.comm_type != 'GPIB':
            return ERR_CALL
        try:
            status = self.instrHandle.read_stb()
            loggings.info("visa spoll command success ")
            return status
        except Exception as e:
            loggings.error("visa spoll command fail " + str(e))
            return e

    def visa_close(self):
        try:
            self.instrHandle.close()
        except BaseException as e:
            loggings.error("visa_close " + str(e))
            raise e
